package com.south.base.test.arithmetic;

import org.junit.Assert;
import org.junit.Test;

/**
 * 实现一个基本的计算器来计算一个简单的字符串表达式的值。
 * 字符串表达式可以包含左括号 ( ，右括号 )，加号 + ，减号 -，非负整数和空格  。
 *
 * @author Administrator
 * @date 2019/6/20 17:10
 */
public class Calculator {

    private int i = -1; // 指针
    private String s;

    public int calculate(String s) {
        this.s = s;
        i = -1;
        return parse();
    }

    public int parse() {
        int ans = 0; // 计算结果
        boolean plus = true; // true:加号, false:减号
        while (i < s.length() - 1) {
            i++;
            switch (s.charAt(i)) {
                case ' ': // 忽略空格
                    continue;
                case '+':
                    plus = true;
                    continue;
                case '-':
                    plus = false;
                    continue;
                case '(':
                    // 遇到左括号表明有新的优先计算区域
                    if (plus) ans += parse();
                    else ans -= parse();
                    continue;
                case ')':
                    // 遇到没有处理的右括号表明优先区域结束
                    return ans;
                default: // 遇到数字
                    if (plus) ans += parseInt();
                    else ans -= parseInt();
            }
        }
        return ans;
    }

    public int parseInt() {
        // 起始位置
        int start = i;
        // 数位
        int pos = 1;
        // 计算结果
        int ans = 0;
        for (; i < s.length(); i++) {
            if (!Character.isDigit(s.charAt(i))) {
                break;
            }
        }
        // 将指针移动到数的结尾
        i--;
        for (int j = i; j >= start; j--) {
            // 从后往前可以避免除法
            ans += pos * (s.charAt(j) - '0');
            pos *= 10;
        }
        return ans;
    }

    @Test
    public void test() {
        Assert.assertEquals(2, calculate("1 + 1"));
        Assert.assertEquals(23, calculate("(1+(4+5+2)-3)+(6+8)"));
        Assert.assertEquals(2147483647, calculate("2147483647"));
    }

}
